package com.ruoyi.common.utils;

import java.io.IOException;
import java.util.*;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Slf4j
@Component
public class PrintUtils {

    /** 开放平台网关 */
    private static String HOST;

    /** 开发平台id */
    private static String APP_ID;

    /** 开发平台秘钥 */
    private static String APP_KEY;

    @Resource
    private RedisCache redisCache;

    @Bean
    public void initPrint() {
        HOST = redisCache.getCacheObject("sys_config:print:dev:host");
        APP_ID = redisCache.getCacheObject("sys_config:print:dev.id");
        APP_KEY = redisCache.getCacheObject("sys_config:print:dev:secret");
    }

    // 创建签名
    private String makeSign(ArrayList<NameValuePair> params) {
        int size = params.size();
        String[] keys = new String[params.size()];
        HashMap<String, String> values = new HashMap<>();
        for (int i = 0; i < size; i++) {
            NameValuePair p = params.get(i);
            keys[i] = p.getName();
            values.put(p.getName(), p.getValue());
        }
        Arrays.sort(keys);

        String sign = "";
        for (int i = 0; i < keys.length; i++) {
            String v = values.get(keys[i]);
            if (!keys[i].equals("sign") && !keys[i].equals("appsecret") && !v.equals("")) {
                if (i > 0) {
                    sign += "&";
                }
                sign += keys[i] + "=" + v;
            }
        }
        sign += "&appsecret=" + APP_KEY;

        return DigestUtils.md5Hex(sign).toUpperCase();
    }

    private String request(String method, String uri, ArrayList<NameValuePair> params) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(4000)    //读取超时
                .setConnectTimeout(1000)   //连接超时
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build();

        // 公共请求参数
        params.add(new BasicNameValuePair("appid", APP_ID));
        params.add(new BasicNameValuePair("timestamp", String.valueOf(System.currentTimeMillis() / 1000)));
        params.add(new BasicNameValuePair("sign", makeSign(params)));

        CloseableHttpResponse response = null;
        String url = HOST + uri;
        if (method.equals("GET")) {
            HttpGet request = new HttpGet(url + "?" + URLEncodedUtils.format(params, "utf-8"));
            response = httpClient.execute(request);
        } else if (method.equals("DELETE")) {
            HttpDelete request = new HttpDelete(url + "?" + URLEncodedUtils.format(params, "utf-8"));
            response = httpClient.execute(request);
        } else if (method.equals("POST")) {
            HttpPost request = new HttpPost(url);
            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
            response = httpClient.execute(request);
        } else if (method.equals("PATCH")) {
            HttpPatch request = new HttpPatch(url);
            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
            response = httpClient.execute(request);
        } else if (method.equals("PUT")) {
            HttpPut request = new HttpPut(url);
            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
            response = httpClient.execute(request);
        }

        if (response == null) {
            throw new ClientProtocolException();
        }

        HttpEntity httpEntity = response.getEntity();
        if (httpEntity == null) {
            throw new ClientProtocolException();
        }

        if (response.getStatusLine().getStatusCode() != 200) {
            throw new ClientProtocolException(EntityUtils.toString(httpEntity));
        }

        return EntityUtils.toString(httpEntity);
    }

    /**
     * 查询打印机状态
     * @return
     */
    public Map<String,Object> printStatus(String printerSn) {
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("msg","打印机异常");
        resultMap.put("status",1);

        ArrayList<NameValuePair> signParams = new ArrayList<>();
        signParams.add(new BasicNameValuePair("sn", printerSn));

        try {
            String result = request("GET", "printer/info", signParams);
            Map<String,Object> body = JSON.parseObject(result, Map.class);
            if (MapUtil.isEmpty(body)) {
                log.error("请求打印机网关发生错误");
                resultMap.put("msg","请求打印机网关发生错误");
                resultMap.put("status",1);
                return resultMap;
            }
            if (!MapUtils.getString(body,"errorcode","-1").equals("0")) {
                log.error("获取打印机信息请求发生错误：{}", MapUtils.getString(body,"errormsg","无"));
                resultMap.put("msg",MapUtils.getString(body,"errormsg","无"));
                resultMap.put("status",1);
                return resultMap;
            }
            resultMap.put("msg","正常");
            resultMap.put("status",0);
            return resultMap;
        } catch (Exception e) {
            Map<String,Object> errorMap = JSON.parseObject(e.getMessage(),Map.class);
            log.error("请求打印机发生错误：{}",MapUtils.getString(errorMap,"errormsg",e.getMessage()));
            resultMap.put("msg",MapUtils.getString(errorMap,"errormsg",e.getMessage()));
            resultMap.put("status",1);
            return resultMap;
        }
    }

    /**
     * 打印订单
     * @return
     */
    public Map<String,Object> printContent(String content, String printerSn) {
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("success", false);
        resultMap.put("msg", "");

        ArrayList<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("sn", printerSn));
        params.add(new BasicNameValuePair("content", content));
        params.add(new BasicNameValuePair("times", String.valueOf(1)));
        try {
            String postResult = request("POST", "printer/print", params);
            Map<String,Object> data = JSON.parseObject(postResult,Map.class);
            if (MapUtils.isEmpty(data)) {
                resultMap.put("success", false);
                resultMap.put("msg", "打印发生错误");
                log.error("打印发生错误：{}",DateTimeUtils.formatDate(new Date()));
                return resultMap;
            }
            if (!MapUtils.getString(data,"errorcode","-1").equals("0")) {
                resultMap.put("success", false);
                resultMap.put("msg", "打印发生错误：" + MapUtils.getString(data,"errormsg"));
                log.error("打印发生错误：{}",MapUtils.getString(data,"errormsg"));
                return resultMap;
            }
            resultMap.put("success", true);
            resultMap.put("msg", "success");
            resultMap.put("data", data);
        } catch (IOException e) {
            resultMap.put("success", false);
            log.error("打印订单发生错误：{}",e.getMessage());
            Map<String,Object> error = JSON.parseObject(e.getMessage(),Map.class);
            if (MapUtils.isEmpty(error)) {
                resultMap.put("msg", e.getMessage());
            } else {
                resultMap.put("msg", MapUtils.getString(error,"errormsg"));
            }
        }
        return resultMap;
    }

    /**
     * 查询订单打印状态
     * @param printId
     * @return
     */
    public boolean getPrintsStatus(String printId) {
        ArrayList<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("id", printId));
        try {
            String result = request("GET", "printer/order/status", params);
            if (StringUtils.isEmpty(result)) {
                return false;
            }
            Map<String,Object> resultMap = JSON.parseObject(result, Map.class);
            if (MapUtils.isEmpty(resultMap)) {
                return false;
            }
            if (!MapUtils.getString(resultMap,"errorcode","-1").equals("0")) {
                return false;
            }
            return MapUtils.getBoolean(resultMap,"status", false);
        } catch (Exception e) {
            return false;
        }
    }
}
